home *** CD-ROM | disk | FTP | other *** search
/ Clickx 47 / Clickx 47.iso / assets / software / Miro_Installer.exe / xulrunner / chrome / toolkit.jar / content / mozapps / extensions / extensions.js < prev    next >
Encoding:
Text File  |  2005-11-06  |  41.8 KB  |  1,137 lines

  1. //@line 37 "/c/mozilla/toolkit/mozapps/extensions/content/extensions.js"
  2.  
  3. ///////////////////////////////////////////////////////////////////////////////
  4. // Globals
  5.  
  6. const kObserverServiceProgID = "@mozilla.org/observer-service;1";
  7. const nsIUpdateItem = Components.interfaces.nsIUpdateItem;
  8.  
  9. var gExtensionManager = null;
  10. var gExtensionsView   = null;
  11. var gWindowState      = "";
  12. var gGetMoreURL       = "";
  13. var gCurrentTheme     = "classic/1.0";
  14. var gDefaultTheme     = "classic/1.0";
  15. var gDownloadManager  = null;
  16. var gObserverIndex    = -1;
  17. var gItemType         = -1;
  18. var gApp              = null;
  19.  
  20. const PREF_EXTENSIONS_GETMORETHEMESURL      = "extensions.getMoreThemesURL";
  21. const PREF_EXTENSIONS_GETMOREEXTENSIONSURL  = "extensions.getMoreExtensionsURL";
  22. const PREF_EXTENSIONS_DSS_ENABLED           = "extensions.dss.enabled";
  23. const PREF_EXTENSIONS_DSS_SWITCHPENDING     = "extensions.dss.switchPending";
  24. const PREF_EM_LAST_SELECTED_SKIN            = "extensions.lastSelectedSkin";
  25. const PREF_GENERAL_SKINS_SELECTEDSKIN       = "general.skins.selectedSkin";
  26.  
  27. const RDFURI_ITEM_ROOT  = "urn:mozilla:item:root";
  28. const PREFIX_ITEM_URI   = "urn:mozilla:item:";
  29.  
  30. const OP_NONE                         = "";
  31. const OP_NEEDS_INSTALL                = "needs-install";
  32. const OP_NEEDS_UPGRADE                = "needs-upgrade";
  33. const OP_NEEDS_UNINSTALL              = "needs-uninstall";
  34. const OP_NEEDS_ENABLE                 = "needs-enable";
  35. const OP_NEEDS_DISABLE                = "needs-disable";
  36.  
  37. ///////////////////////////////////////////////////////////////////////////////
  38. // Utility Functions 
  39.  
  40. function LOG(msg) {
  41.   dump("*** " + msg + "\n");
  42. }
  43.  
  44. function getIDFromResourceURI(aURI) 
  45. {
  46.   if (aURI.substring(0, PREFIX_ITEM_URI.length) == PREFIX_ITEM_URI) 
  47.     return aURI.substring(PREFIX_ITEM_URI.length);
  48.   return aURI;
  49. }
  50.  
  51. function openURL(aURL)
  52. {
  53. //@line 90 "/c/mozilla/toolkit/mozapps/extensions/content/extensions.js"
  54.   var uri = Components.classes["@mozilla.org/network/io-service;1"]
  55.                       .getService(Components.interfaces.nsIIOService)
  56.                       .newURI(aURL, null, null);
  57.  
  58.   var protocolSvc = Components.classes["@mozilla.org/uriloader/external-protocol-service;1"]
  59.                               .getService(Components.interfaces.nsIExternalProtocolService);
  60.   protocolSvc.loadUrl(uri);
  61. //@line 101 "/c/mozilla/toolkit/mozapps/extensions/content/extensions.js"
  62. }
  63.  
  64. function flushDataSource()
  65. {
  66.   var rds = gExtensionManager.datasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
  67.   if (rds)
  68.     rds.Flush();
  69. }
  70.  
  71. function setRestartMessage(aItem)
  72. {
  73.   var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]
  74.                       .getService(Components.interfaces.nsIStringBundleService);
  75.   var extensionStrings = sbs.createBundle("chrome://mozapps/locale/extensions/extensions.properties");
  76.   var brandStrings = sbs.createBundle("chrome://branding/locale/brand.properties");
  77.   var brandShortName = brandStrings.GetStringFromName("brandShortName");
  78.   var themeName = aItem.getAttribute("name");
  79.   var restartMessage = extensionStrings.formatStringFromName("dssSwitchAfterRestart", 
  80.                                                              [brandShortName], 1);
  81.   for (var i = 0; i < gExtensionsView.childNodes.length; ++i) {
  82.     var item = gExtensionsView.childNodes[i];
  83.     if (item.hasAttribute("oldDescription")) {
  84.       item.setAttribute("description", item.getAttribute("oldDescription"));
  85.       item.removeAttribute("oldDescription");
  86.     }
  87.   }
  88.   aItem.setAttribute("oldDescription", aItem.getAttribute("description"));
  89.   aItem.setAttribute("description", restartMessage);
  90. }
  91.  
  92. ///////////////////////////////////////////////////////////////////////////////
  93. // Event Handlers
  94. function onExtensionUpdateNow(aEvent)
  95. {
  96.   var item = gExtensionManager.getItemForID(getIDFromResourceURI(
  97.     aEvent.target.id));
  98.   gExtensionManager.addDownloads([item], 1, true);
  99. }
  100.  
  101. ///////////////////////////////////////////////////////////////////////////////
  102. // Startup, Shutdown
  103. function Startup() 
  104. {
  105.   gWindowState = window.location.search.substr("?type=".length, window.location.search.length);
  106.   
  107.   var isExtensions = gWindowState == "extensions";
  108.   gItemType   = isExtensions ? nsIUpdateItem.TYPE_EXTENSION : nsIUpdateItem.TYPE_THEME;
  109.   var typeCondition = document.getElementById("typeCondition");
  110.   typeCondition.setAttribute("object", gItemType);
  111.   
  112.   document.documentElement.setAttribute("windowtype", document.documentElement.getAttribute("windowtype") + "-" + gWindowState);
  113.  
  114.   gExtensionsView = document.getElementById("extensionsView");
  115.   gExtensionsView.setAttribute("state", gWindowState);
  116.   gExtensionManager = Components.classes["@mozilla.org/extensions/manager;1"]
  117.                                 .getService(Components.interfaces.nsIExtensionManager);
  118.   gApp = Components.classes["@mozilla.org/xre/app-info;1"].getService(Components.interfaces.nsIXULAppInfo)
  119.                    .QueryInterface(Components.interfaces.nsIXULRuntime);
  120.  
  121.   // Extension Command Updating is handled by a command controller.
  122.   gExtensionsView.controllers.appendController(gExtensionsViewController);
  123.  
  124.   gExtensionsView.addEventListener("extension-updatenow", onExtensionUpdateNow, false);
  125.  
  126.   var pref = Components.classes["@mozilla.org/preferences-service;1"]
  127.                        .getService(Components.interfaces.nsIPrefBranch);
  128.   var defaultPref = pref.QueryInterface(Components.interfaces.nsIPrefService)
  129.                         .getDefaultBranch(null);
  130.   if (!isExtensions) {
  131.     gExtensionsView.addEventListener("select", onThemeSelect, false);
  132.  
  133.     try {
  134.         gCurrentTheme = pref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
  135.         gDefaultTheme = defaultPref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
  136.     }
  137.     catch (e) { }
  138.  
  139.     var useThemeButton = document.getElementById("useThemeButton");
  140.     useThemeButton.hidden = false;
  141.  
  142.     var optionsButton = document.getElementById("optionsButton");
  143.     optionsButton.hidden = true;
  144.   }
  145.  
  146.   // Finally, update the UI. 
  147.   gExtensionsView.database.AddDataSource(gExtensionManager.datasource);
  148.   gExtensionsView.setAttribute("ref", RDFURI_ITEM_ROOT);
  149.   gExtensionsView.focus();
  150.   
  151.   var extensionsStrings = document.getElementById("extensionsStrings");
  152.   document.title = extensionsStrings.getString(gWindowState + "Title");
  153.   
  154.   gExtensionsViewController.onCommandUpdate(); 
  155.   
  156.   gGetMoreURL = pref.getComplexValue(isExtensions ? PREF_EXTENSIONS_GETMOREEXTENSIONSURL 
  157.                                                   : PREF_EXTENSIONS_GETMORETHEMESURL, 
  158.                                      Components.interfaces.nsIPrefLocalizedString).data;
  159.   var app = Components.classes["@mozilla.org/xre/app-info;1"]
  160.                       .getService(Components.interfaces.nsIXULAppInfo);
  161.   gGetMoreURL = gGetMoreURL.replace(/%APPID%/g, app.ID);
  162.   // Update various pieces of state-dependant UI
  163.   var getMore = document.getElementById("getMore");
  164.   getMore.setAttribute("value", getMore.getAttribute(isExtensions ? "valueextensions" : "valuethemes"));
  165.   getMore.setAttribute("tooltiptext", getMore.getAttribute(isExtensions ? "tooltiptextextensions" : "tooltiptextthemes"));
  166.   getMore.setAttribute('href', gGetMoreURL);
  167.   
  168.   if (!isExtensions) {
  169.     var themePreviewArea = document.getElementById("themePreviewArea");
  170.     themePreviewArea.hidden = false;
  171.     gExtensionsView.removeAttribute("flex");
  172.     gExtensionsView.style.width = extensionsStrings.getString("themesManagerLeftColumn");
  173.   }
  174.   
  175.   // Set Initial Size
  176.   var win = document.documentElement;
  177.   if (!win.hasAttribute("width") || !win.hasAttribute("height")) {
  178.     win.setAttribute("width", isExtensions ? (extensionsStrings.getString("extensionsManagerWidth")) : (extensionsStrings.getString("themesManagerWidth")));
  179.     win.setAttribute("height", isExtensions ? (extensionsStrings.getString("extensionsManagerHeight")) : (extensionsStrings.getString("themesManagerHeight")));
  180.   }
  181.  
  182.   // Now look and see if we're being opened by XPInstall
  183.   gDownloadManager = new XPInstallDownloadManager();
  184.   var os = Components.classes["@mozilla.org/observer-service;1"]
  185.                      .getService(Components.interfaces.nsIObserverService);
  186.   os.addObserver(gDownloadManager, "xpinstall-download-started", false);
  187.  
  188.   gObserverIndex = gExtensionManager.addUpdateListener(gDownloadManager);
  189.   
  190.   if ("arguments" in window) {
  191.     try {
  192.       var params = window.arguments[0].QueryInterface(Components.interfaces.nsIDialogParamBlock);
  193.       gDownloadManager.addDownloads(params);
  194.     }
  195.     catch (e) {
  196.       if (window.arguments[0] == "updatecheck")
  197.         performUpdate();
  198.     }
  199.   }
  200.   
  201.   // Set the tooltips
  202.   if (!isExtensions) {
  203. //@line 243 "/c/mozilla/toolkit/mozapps/extensions/content/extensions.js"
  204.     document.getElementById("installButton").setAttribute("tooltiptext", extensionsStrings.getString("cmdInstallTooltipTheme"));
  205. //@line 245 "/c/mozilla/toolkit/mozapps/extensions/content/extensions.js"
  206.     document.getElementById("uninstallButton").setAttribute("tooltiptext", extensionsStrings.getString("cmdUninstallTooltipTheme"));
  207.     document.getElementById("updateButton").setAttribute("tooltiptext", extensionsStrings.getString("cmdUpdateTooltipTheme"));
  208.   }
  209. }
  210.  
  211. function Shutdown() 
  212. {
  213.   if (gWindowState != "extensions")
  214.     gExtensionsView.removeEventListener("select", onThemeSelect, false);
  215.  
  216.   gExtensionsView.removeEventListener("extension-updatenow", onExtensionUpdateNow, false);
  217.  
  218.   gExtensionsView.database.RemoveDataSource(gExtensionManager.datasource);
  219.  
  220.   gExtensionManager.removeUpdateListenerAt(gObserverIndex);
  221.  
  222.   var os = Components.classes["@mozilla.org/observer-service;1"]
  223.                      .getService(Components.interfaces.nsIObserverService);
  224.   if (gDownloadManager) 
  225.     os.removeObserver(gDownloadManager, "xpinstall-download-started");
  226. }
  227.  
  228. ///////////////////////////////////////////////////////////////////////////////
  229. //
  230. // XPInstall
  231. //
  232.  
  233. function getURLSpecFromFile(aFile)
  234. {
  235.   var ioServ = Components.classes["@mozilla.org/network/io-service;1"]
  236.                           .getService(Components.interfaces.nsIIOService);
  237.   var fph = ioServ.getProtocolHandler("file").QueryInterface(Components.interfaces.nsIFileProtocolHandler);
  238.   return fph.getURLSpecFromFile(aFile);
  239. }
  240.  
  241. function XPInstallDownloadManager()
  242. {
  243.   var extensionsStrings = document.getElementById("extensionsStrings");
  244.   this._statusFormatKBMB  = extensionsStrings.getString("statusFormatKBMB");
  245.   this._statusFormatKBKB  = extensionsStrings.getString("statusFormatKBKB");
  246.   this._statusFormatMBMB  = extensionsStrings.getString("statusFormatMBMB");
  247. }
  248.  
  249. XPInstallDownloadManager.prototype = {
  250.   _statusFormat     : null,
  251.   _statusFormatKBMB : null,
  252.   _statusFormatKBKB : null,
  253.   _statusFormatMBMB : null,
  254.   
  255.   observe: function (aSubject, aTopic, aData) 
  256.   {
  257.     switch (aTopic) {
  258.       case "xpinstall-download-started":
  259.         var params = aSubject.QueryInterface(Components.interfaces.nsISupportsArray);
  260.         var paramBlock = params.GetElementAt(0).QueryInterface(Components.interfaces.nsISupportsInterfacePointer);
  261.         paramBlock = paramBlock.data.QueryInterface(Components.interfaces.nsIDialogParamBlock);
  262.         this.addDownloads(paramBlock);
  263.         break;
  264.     }
  265.   },
  266.   
  267.   addDownloads: function (aParams)
  268.   {
  269.     var numXPInstallItems = aParams.GetInt(1);
  270.     var isExtensions = gWindowState == "extensions";
  271.     
  272.     var items = [];
  273.     for (var i = 0; i < numXPInstallItems;) {
  274.       var displayName = aParams.GetString(i++);
  275.       var url = aParams.GetString(i++);
  276.       var iconURL = aParams.GetString(i++);
  277.       if (!iconURL) { 
  278.         iconURL = isExtensions ? "chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png" : 
  279.                                  "chrome://mozapps/skin/extensions/themeGeneric.png";
  280.       }
  281.       
  282.       var type = isExtensions ? nsIUpdateItem.TYPE_EXTENSION : nsIUpdateItem.TYPE_THEME;
  283.       var item = Components.classes["@mozilla.org/updates/item;1"]
  284.                            .createInstance(Components.interfaces.nsIUpdateItem);
  285.       item.init(url, " ", "app-profile", "", "", displayName, url, "", iconURL, "", type);
  286.       items.push(item);
  287.  
  288.       // Advance the enumerator
  289.       var certName = aParams.GetString(i++);
  290.     }
  291.     
  292.     gExtensionManager.addDownloads(items, items.length, false);
  293.     gExtensionsView.scrollBoxObject.ensureElementIsVisible(gExtensionsView.lastChild);
  294.   },
  295.   
  296.   getElementForAddon: function(aAddon) 
  297.   {
  298.     var element = document.getElementById(PREFIX_ITEM_URI + aAddon.id);
  299.     if (aAddon.id == aAddon.xpiURL)
  300.       element = document.getElementById(aAddon.xpiURL);
  301.     return element;
  302.   },
  303.  
  304.   /////////////////////////////////////////////////////////////////////////////  
  305.   // nsIAddonUpdateListener
  306.   onStateChange: function (aAddon, aState, aValue)
  307.   {
  308.     const nsIXPIProgressDialog = Components.interfaces.nsIXPIProgressDialog;
  309.     var element = this.getElementForAddon(aAddon);
  310.     if (!element) return;
  311.     switch (aState) {
  312.       case nsIXPIProgressDialog.DOWNLOAD_START:
  313.         element.setAttribute("state", "waiting");
  314.  
  315.         var extensionsStrings = document.getElementById("extensionsStrings");
  316.         element.setAttribute("description",
  317.                              extensionsStrings.getString("installWaiting"));
  318.  
  319.         element.setAttribute("progress", "0");
  320.         break;
  321.       case nsIXPIProgressDialog.DOWNLOAD_DONE:
  322.         element.setAttribute("progress", "100");
  323.         break;
  324.       case nsIXPIProgressDialog.INSTALL_START:
  325.         element.setAttribute("state", "installing");
  326.  
  327.         extensionsStrings = document.getElementById("extensionsStrings");
  328.         element.setAttribute("description",
  329.                              extensionsStrings.getString("installInstalling"));
  330.         break;
  331.       case nsIXPIProgressDialog.INSTALL_DONE:
  332.         dump("*** state change = " + aAddon.xpiURL + ", state = " + aState + ", value = " + aValue + "\n");
  333.         element.setAttribute("state", "done");
  334.         extensionsStrings = document.getElementById("extensionsStrings");
  335.         element.setAttribute("description",
  336.                              extensionsStrings.getString("installSuccess"));
  337.         var msg;
  338.         if (aValue != 0 && aValue != 999) {
  339.           var xpinstallStrings = document.getElementById("xpinstallStrings");
  340.           try {
  341.             msg = xpinstallStrings.getString("error" + aValue);
  342.           }
  343.           catch (e) {
  344.             msg = xpinstallStrings.getFormattedString("unknown.error", [aValue]);
  345.           }
  346.           var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]
  347.                               .getService(Components.interfaces.nsIStringBundleService);
  348.           var extensionStrings = sbs.createBundle("chrome://mozapps/locale/extensions/extensions.properties");
  349.           var title = extensionStrings.GetStringFromName("errorInstallTitle");
  350.  
  351.           var brandStrings = sbs.createBundle("chrome://branding/locale/brand.properties");
  352.           var brandShortName = brandStrings.GetStringFromName("brandShortName");
  353.           var params = [brandShortName, aAddon.xpiURL, msg];
  354.           var message = extensionStrings.formatStringFromName("errorInstallMsg", params, params.length);
  355.  
  356.           var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  357.                              .getService(Components.interfaces.nsIPromptService);
  358.           ps.alert(window, title, message);
  359.           element.setAttribute("status", msg);
  360.         }
  361.         // Remove the dummy, since we installed successfully (only if we're a URL, 
  362.         // not a download operation on an existing item.
  363.         var type = gWindowState == "extensions" ? nsIUpdateItem.TYPE_EXTENSION
  364.                                                 : nsIUpdateItem.TYPE_THEME;
  365.         gExtensionManager.removeDownload(aAddon.xpiURL);
  366.         break;
  367.       case nsIXPIProgressDialog.DIALOG_CLOSE:
  368.         break;
  369.     }
  370.   },
  371.   
  372.   _urls: { },
  373.   onProgress: function (aAddon, aValue, aMaxValue)
  374.   {
  375.     var element = this.getElementForAddon(aAddon);
  376.     if (!element) return;
  377.     var percent = Math.round((aValue / aMaxValue) * 100);
  378.     if (percent > 1 && !(aAddon.xpiURL in this._urls)) {
  379.       this._urls[aAddon.xpiURL] = true;
  380.       element.setAttribute("state", "downloading");
  381.     }
  382.     element.setAttribute("progress", percent);
  383.     
  384.     var KBProgress = parseInt(aValue/1024 + .5);
  385.     var KBTotal = parseInt(aMaxValue/1024 + .5);
  386.     element.setAttribute("status", this._formatKBytes(KBProgress, KBTotal));
  387.   },
  388.   
  389.   _replaceInsert: function ( text, index, value ) 
  390.   {
  391.     var result = text;
  392.     var regExp = new RegExp( "#"+index );
  393.     result = result.replace( regExp, value );
  394.     return result;
  395.   },
  396.   
  397.   // aBytes     aTotalKBytes    returns:
  398.   // x, < 1MB   y < 1MB         x of y KB
  399.   // x, < 1MB   y >= 1MB        x KB of y MB
  400.   // x, >= 1MB  y >= 1MB        x of y MB
  401.   _formatKBytes: function (aKBytes, aTotalKBytes)
  402.   {
  403.     var progressHasMB = parseInt(aKBytes/1000) > 0;
  404.     var totalHasMB = parseInt(aTotalKBytes/1000) > 0;
  405.     
  406.     var format = "";
  407.     if (!progressHasMB && !totalHasMB) {
  408.       format = this._statusFormatKBKB;
  409.       format = this._replaceInsert(format, 1, aKBytes);
  410.       format = this._replaceInsert(format, 2, aTotalKBytes);
  411.     }
  412.     else if (progressHasMB && totalHasMB) {
  413.       format = this._statusFormatMBMB;
  414.       format = this._replaceInsert(format, 1, (aKBytes / 1000).toFixed(1));
  415.       format = this._replaceInsert(format, 2, (aTotalKBytes / 1000).toFixed(1));
  416.     }
  417.     else if (totalHasMB && !progressHasMB) {
  418.       format = this._statusFormatKBMB;
  419.       format = this._replaceInsert(format, 1, aKBytes);
  420.       format = this._replaceInsert(format, 2, (aTotalKBytes / 1000).toFixed(1));
  421.     }
  422.     else {
  423.       // This is an undefined state!
  424.       dump("*** huh?!\n");
  425.     }
  426.     
  427.     return format;  
  428.   },
  429.  
  430.   /////////////////////////////////////////////////////////////////////////////
  431.   // nsISupports
  432.   QueryInterface: function (aIID) 
  433.   {
  434.     if (!aIID.equals(Components.interfaces.nsIAddonUpdateListener) &&
  435.         !aIID.equals(Components.interfaces.nsISupports))
  436.       throw Components.results.NS_ERROR_NO_INTERFACE;
  437.     return this;
  438.   }
  439. };
  440.  
  441. ///////////////////////////////////////////////////////////////////////////////
  442. //
  443. // Update Listener
  444. //
  445. function UpdateCheckListener() {
  446.   this._addons = [];
  447. }
  448. UpdateCheckListener.prototype = {
  449.   /**
  450.    * A list of addons we've found updates to in this update check transaction.
  451.    */
  452.   _addons: [],
  453.   
  454.   /**
  455.    * See nsIExtensionManager.idl
  456.    */
  457.   onUpdateStarted: function() {
  458.     gExtensionsView.setAttribute("update-check", "true");
  459.     var command = document.getElementById("cmd_update");
  460.     command.setAttribute("disabled", "true");
  461.     command = document.getElementById("cmd_update_all");
  462.     command.setAttribute("disabled", "true");
  463.   },
  464.   
  465.   /**
  466.    * See nsIExtensionManager.idl
  467.    */
  468.   onUpdateEnded: function() {
  469.     gExtensionsView.removeAttribute("update-check");
  470.     var command = document.getElementById("cmd_update");
  471.     gExtensionsViewController.updateCommand(command);
  472.     command = document.getElementById("cmd_update_all");
  473.     command.removeAttribute("disabled");
  474.     
  475.     // Show message to user listing extensions for which updates are available
  476.     // and prompt to install now.
  477.     if (this._addons.length == 1) {
  478.       var element = document.getElementById(PREFIX_ITEM_URI + this._addons[0].id);
  479.       gExtensionsView.scrollBoxObject.scrollToElement(element);
  480.     }
  481.     else if (this._addons.length > 1) {
  482.       var strings = document.getElementById("extensionsStrings");
  483.       var brandName = document.getElementById("brandStrings").getString("brandShortName");
  484.       var params = {
  485.         message1: strings.getFormattedString("updatesAvailableMessage1",
  486.                                              [brandName]),
  487.         message2: strings.getString("updatesAvailableMessage2"),
  488.         title: strings.getString("updatesAvailableTitle"),
  489.         buttons: {
  490.           accept: { label: strings.getString("updatesAvailableAccept"),
  491.                     focused: true },
  492.           cancel: { label: strings.getString("updatesAvailableCancel") }
  493.         }
  494.       }
  495.       var names = [];
  496.       for (var i = 0; i < this._addons.length; ++i) {
  497.         var addon = this._addons[i];
  498.         var existingItem = gExtensionManager.getItemForID(addon.id);
  499.         var name = strings.getFormattedString("itemFormat", 
  500.                                               [this._addons[i].name, 
  501.                                                existingItem.version,
  502.                                                this._addons[i].version]);
  503.         names.push(name);
  504.       }
  505.       openDialog("chrome://mozapps/content/extensions/list.xul", "", 
  506.                  "titlebar,modal", names, params);
  507.       if (params.result == "accept") 
  508.         gExtensionManager.addDownloads(this._addons, this._addons.length, true);
  509.     }
  510.   },
  511.   
  512.   /**
  513.    * See nsIExtensionManager.idl
  514.    */
  515.   onAddonUpdateStarted: function(addon) {
  516.     var element = document.getElementById(PREFIX_ITEM_URI + addon.id);
  517.     element.setAttribute("loading", "true");
  518.   },
  519.   
  520.   /**
  521.    * See nsIExtensionManager.idl
  522.    */
  523.   onAddonUpdateEnded: function(addon, status) {
  524.     var element = document.getElementById(PREFIX_ITEM_URI + addon.id);
  525.     element.removeAttribute("loading");
  526.     const nsIAUCL = Components.interfaces.nsIAddonUpdateCheckListener;
  527.     var strings = document.getElementById("extensionsStrings");
  528.     switch (status) {
  529.     case nsIAUCL.STATUS_UPDATE:
  530.       this._addons.push(addon);
  531.       break;
  532.     case nsIAUCL.STATUS_FAILURE:
  533.       element.setAttribute("description", strings.getString("updateFailedMsg"));
  534.       break;
  535.     case nsIAUCL.STATUS_DISABLED:
  536.       element.setAttribute("description", strings.getString("updateDisabledMsg")); 
  537.       break;
  538.     }
  539.   },
  540.   
  541.   /**
  542.    * See nsISupports.idl
  543.    */
  544.   QueryInterface: function(iid) {
  545.     if (!iid.equals(Components.interfaces.nsIAddonUpdateCheckListener) &&
  546.         !iid.equals(Components.interfaces.nsISupports))
  547.       throw Components.results.NS_ERROR_NO_INTERFACE;
  548.     return this;
  549.   }
  550. };
  551.  
  552.  
  553. ///////////////////////////////////////////////////////////////////////////////
  554. //
  555. // View Event Handlers
  556. //
  557. function onViewDoubleClick(aEvent)
  558. {
  559.   if (aEvent.button != 0)
  560.     return;
  561.  
  562.   switch (gWindowState) {
  563.     case "extensions":
  564.       gExtensionsViewController.doCommand('cmd_options');
  565.       break;
  566.     case "themes":
  567.       gExtensionsViewController.doCommand('cmd_useTheme');
  568.       break;
  569.   }
  570. }
  571.  
  572. function onThemeSelect(aEvent)
  573. {
  574.   if (gWindowState != "themes")
  575.     return;
  576.  
  577.   var previewImageDeck = document.getElementById("previewImageDeck");
  578.   if (!gExtensionsView.selectedItem) {
  579.     previewImageDeck.setAttribute("selectedIndex", "0");
  580.     return;
  581.   }
  582.   var url = gExtensionsView.selectedItem.getAttribute("previewImage");
  583.   if (url) {
  584.     previewImageDeck.setAttribute("selectedIndex", "2");
  585.     var previewImage = document.getElementById("previewImage");
  586.     previewImage.setAttribute("src", url);
  587.   }
  588.   else
  589.     previewImageDeck.setAttribute("selectedIndex", "1");
  590. }
  591.  
  592. ///////////////////////////////////////////////////////////////////////////////
  593. // View Context Menus
  594. var gExtensionContextMenus = ["menuitem_options", "menuitem_homepage", "menuitem_about", 
  595.                               "menuseparator_1", "menuitem_uninstall", "menuitem_update",
  596.                               "menuitem_enable", "menuitem_disable", "menuseparator_2", 
  597.                               "menuitem_moveTop", "menuitem_moveUp", "menuitem_moveDn"];
  598. var gThemeContextMenus = ["menuitem_useTheme", "menuitem_homepage", "menuitem_about", 
  599.                           "menuseparator_1", "menuitem_uninstall", "menuitem_update",
  600.                           "menuitem_enable"];
  601.  
  602. function buildContextMenu(aEvent)
  603. {
  604.   if (aEvent.target.id != "extensionContextMenu")
  605.     return false;
  606.     
  607.   var popup = document.getElementById("extensionContextMenu");
  608.   while (popup.hasChildNodes())
  609.     popup.removeChild(popup.firstChild);
  610.  
  611.   var isExtensions = gWindowState == "extensions";
  612.  
  613.   var menus = isExtensions ? gExtensionContextMenus : gThemeContextMenus;  
  614.   for (var i = 0; i < menus.length; ++i) {
  615.     var clonedMenu = document.getElementById(menus[i]).cloneNode(true);
  616.     clonedMenu.id = clonedMenu.id + "_clone";
  617.     popup.appendChild(clonedMenu);
  618.   }
  619.  
  620.   var extensionsStrings = document.getElementById("extensionsStrings");
  621.   var menuitem_about = document.getElementById("menuitem_about_clone");
  622.   var selectedItem = gExtensionsView.selectedItem;
  623.   var name = selectedItem ? selectedItem.getAttribute("name") : "";
  624.   menuitem_about.setAttribute("label", extensionsStrings.getFormattedString("aboutExtension", [name]));
  625.   
  626.   if (isExtensions) {
  627.     var canEnable = gExtensionsViewController.isCommandEnabled("cmd_reallyEnable");
  628.     var menuitemToShow, menuitemToHide;
  629.     if (canEnable) {
  630.       menuitemToShow = document.getElementById("menuitem_enable_clone");
  631.       menuitemToHide = document.getElementById("menuitem_disable_clone");
  632.     }
  633.     else {
  634.       menuitemToShow = document.getElementById("menuitem_disable_clone");
  635.       menuitemToHide = document.getElementById("menuitem_enable_clone");
  636.     }
  637.     menuitemToShow.hidden = false;
  638.     menuitemToHide.hidden = true;
  639.   }
  640.   else {
  641.     var enableMenu = document.getElementById("menuitem_enable_clone");
  642.     if (gExtensionsView.selectedItem &&
  643.        (gExtensionsView.selectedItem.getAttribute("compatible") == "false" ||
  644.         gExtensionsView.selectedItem.disabled))
  645.       // don't let the user activate incompatible themes, but show a (disabled) Enable
  646.       // menuitem to give visual feedback; it's disabled because cmd_enable returns false
  647.       enableMenu.hidden = false;
  648.     else {
  649.       enableMenu.hidden = true;
  650.     }
  651.   }
  652.     
  653.   return true;
  654. }
  655.  
  656. ///////////////////////////////////////////////////////////////////////////////
  657. // Drag and Drop
  658.  
  659. var gExtensionsDNDObserver =
  660. {
  661.   _ioServ: null,
  662.   _canDrop: false,
  663.   
  664.   _ensureServices: function ()
  665.   {
  666.     if (!this._ioServ)
  667.       this._ioServ = Components.classes["@mozilla.org/network/io-service;1"]
  668.                                .getService(Components.interfaces.nsIIOService);
  669.   },
  670.  
  671.   // returns a JS object whose properties are used by xpinstall
  672.   _getDataFromDragSession: function (aDragSession, aPosition)
  673.   {
  674.     var fileData = { };
  675.     // if this fails we do not have valid data to drop
  676.     try {
  677.       var xfer = Components.classes["@mozilla.org/widget/transferable;1"]
  678.                            .createInstance(Components.interfaces.nsITransferable);
  679.       xfer.addDataFlavor("text/x-moz-url");
  680.       xfer.addDataFlavor("application/x-moz-file", "nsIFile");
  681.       aDragSession.getData(xfer, aPosition);
  682.  
  683.       var flavour = { }, data = { }, length = { };
  684.       xfer.getAnyTransferData(flavour, data, length);
  685.       var selectedFlavour = this.getSupportedFlavours().flavourTable[flavour.value];
  686.       var xferData = new FlavourData(data.value, length.value, selectedFlavour);
  687.  
  688.       var fileURL = transferUtils.retrieveURLFromData(xferData.data,
  689.                                                       xferData.flavour.contentType);
  690.       fileData.fileURL = fileURL;
  691.  
  692.       var uri = this._ioServ.newURI(fileURL, null, null);
  693.       var url = uri.QueryInterface(Components.interfaces.nsIURL);
  694.       fileData.fileName = url.fileName;
  695.  
  696.       switch (url.fileExtension) {
  697.         case "xpi":
  698.           fileData.type = nsIUpdateItem.TYPE_EXTENSION;
  699.           break;
  700.         case "jar":
  701.           fileData.type = nsIUpdateItem.TYPE_THEME;
  702.           break;
  703.         default:
  704.           return null;
  705.       }
  706.     }
  707.     catch (e) {
  708.       return null;
  709.     }
  710.  
  711.     return fileData;
  712.   },
  713.  
  714.   canDrop: function (aEvent, aDragSession) { return this._canDrop; },
  715.  
  716.   onDragEnter: function (aEvent, aDragSession)
  717.   {
  718.     // XXXrstrong - bug 269568, GTK2 drag and drop is returning invalid data for
  719.     // dragenter and dragover. To workaround this we always set canDrop to true
  720.     // and just use the xfer data returned in ondrop which is valid.
  721. //@line 761 "/c/mozilla/toolkit/mozapps/extensions/content/extensions.js"
  722.     this._ensureServices();
  723.  
  724.     var count = aDragSession.numDropItems;
  725.     for (var i = 0; i < count; ++i) {
  726.       var fileData = this._getDataFromDragSession(aDragSession, i);
  727.       if (!fileData) {
  728.         this._canDrop = false;
  729.         return;
  730.       }
  731.     }
  732. //@line 772 "/c/mozilla/toolkit/mozapps/extensions/content/extensions.js"
  733.     this._canDrop = true;
  734.   },
  735.  
  736.   onDragOver: function (aEvent, aFlavor, aDragSession) { },
  737.  
  738.   onDrop: function(aEvent, aXferData, aDragSession)
  739.   {
  740.     this._ensureServices();
  741.     
  742.     var xpinstallObj = { };
  743.     var themes = { };
  744.     var xpiCount = 0;
  745.     var themeCount = 0;
  746.     
  747.     var count = aDragSession.numDropItems;
  748.     for (var i = 0; i < count; ++i) {
  749.       var fileData = this._getDataFromDragSession(aDragSession, i);
  750.       if (!fileData)
  751.         continue;
  752.  
  753.       if (fileData.type == nsIUpdateItem.TYPE_EXTENSION) {
  754.         xpinstallObj[fileData.fileName] = fileData.fileURL;
  755.         ++xpiCount;
  756.       }
  757.       else if (fileData.type == nsIUpdateItem.TYPE_THEME) {
  758.         themes[fileData.fileName] = fileData.fileURL;
  759.         ++themeCount;
  760.       }
  761.     }
  762.  
  763.     if (xpiCount > 0) 
  764.       InstallTrigger.install(xpinstallObj);
  765.     if (themeCount > 0) {
  766.       for (var fileName in themes)
  767.         InstallTrigger.installChrome(InstallTrigger.SKIN, themes[fileName], fileName);
  768.     }
  769.   },
  770.   _flavourSet: null,  
  771.   getSupportedFlavours: function ()
  772.   {
  773.     if (!this._flavourSet) {
  774.       this._flavourSet = new FlavourSet();
  775.       this._flavourSet.appendFlavour("text/x-moz-url");
  776.       this._flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
  777.     }
  778.     return this._flavourSet;
  779.   }
  780. };
  781.  
  782. ///////////////////////////////////////////////////////////////////////////////
  783. // Command Updating and Command Handlers
  784.  
  785. function canWriteToLocation(element)
  786. {
  787.   var installLocation = null;
  788.   if (element) {
  789.     var id = getIDFromResourceURI(element.id)
  790.     installLocation = gExtensionManager.getInstallLocation(id);
  791.   }
  792.   return installLocation ? installLocation.canAccess : false;
  793. }
  794.  
  795. function performUpdate()
  796. {
  797.   gExtensionsViewController.commands.cmd_update(null);
  798. }
  799.  
  800. var gExtensionsViewController = {
  801.   supportsCommand: function (aCommand)
  802.   {
  803.     var commandNode = document.getElementById(aCommand);
  804.     return commandNode && (commandNode.parentNode == document.getElementById("extensionsCommands"));
  805.   },
  806.  
  807.   isCommandEnabled: function (aCommand)
  808.   {
  809.     var selectedItem = gExtensionsView.selectedItem;
  810.     if (selectedItem) {
  811.       if (selectedItem.getAttribute("downloadURL") != "")
  812.         return false;
  813.       var opType = selectedItem.getAttribute("opType");
  814.     }
  815.  
  816.     switch (aCommand) {
  817.     case "cmd_close":
  818.       return true;
  819.     case "cmd_useTheme":
  820.       return selectedItem &&
  821.              !selectedItem.disabled &&
  822.              opType != OP_NEEDS_UNINSTALL &&
  823.              gCurrentTheme != selectedItem.getAttribute("internalName");
  824.     case "cmd_options":
  825.       return selectedItem &&
  826.              !selectedItem.disabled &&
  827.              !gApp.inSafeMode &&
  828.              opType == OP_NONE &&
  829.              selectedItem.getAttribute("optionsURL") != "";
  830.     case "cmd_about":
  831.       return selectedItem &&
  832.              opType != OP_NEEDS_INSTALL;
  833.     case "cmd_homepage":
  834.       return selectedItem && selectedItem.getAttribute("homepageURL") != "";
  835.     case "cmd_uninstall":
  836.       if (gWindowState != "extensions") {
  837.         // uninstall is never available for the default theme
  838.         return (selectedItem && 
  839.                 selectedItem.getAttribute("internalName") != gDefaultTheme &&
  840.                 opType != OP_NEEDS_UNINSTALL &&
  841.                 selectedItem.getAttribute("locked") != "true" &&
  842.                 canWriteToLocation(selectedItem));
  843.       }
  844.       return selectedItem &&
  845.              opType != OP_NEEDS_UNINSTALL &&
  846.              selectedItem.getAttribute("locked") != "true" &&
  847.              canWriteToLocation(selectedItem);
  848.     case "cmd_update":
  849.       return selectedItem &&
  850.              selectedItem.getAttribute("updateable") != "false" &&
  851.              !gExtensionsView.hasAttribute("update-check");
  852.     case "cmd_update_all":
  853.       return gExtensionsView.children.length > 0 &&
  854.              !gExtensionsView.hasAttribute("update-check");
  855.     case "cmd_reallyEnable":
  856.     // controls whether to show Enable or Disable in extensions' context menu
  857.       return selectedItem && 
  858.             (selectedItem.disabled &&
  859.              opType != OP_NEEDS_ENABLE ||
  860.              opType == OP_NEEDS_DISABLE ||
  861.              opType == OP_NEEDS_UNINSTALL);
  862.     case "cmd_enable":
  863.     //controls wheter the Enable/Disable menuitem is enabled
  864.       return selectedItem && 
  865.              opType != OP_NEEDS_ENABLE &&
  866.              opType != OP_NEEDS_INSTALL &&
  867.              opType != OP_NEEDS_UPGRADE &&
  868.              selectedItem.getAttribute("compatible") != "false";
  869.     case "cmd_disable":
  870.       return selectedItem &&
  871.             (opType == OP_NONE ||
  872.              opType == OP_NEEDS_ENABLE);
  873.     case "cmd_movetop":
  874.       return selectedItem && (gExtensionsView.children[0] != selectedItem);
  875.     case "cmd_moveup":
  876.       return selectedItem && (gExtensionsView.children[0] != selectedItem);
  877.     case "cmd_movedn":
  878.       var children = gExtensionsView.children;
  879.       return selectedItem && (children[children.length-1] != selectedItem);
  880. //@line 920 "/c/mozilla/toolkit/mozapps/extensions/content/extensions.js"
  881.     case "cmd_install":
  882.       return true;   
  883. //@line 923 "/c/mozilla/toolkit/mozapps/extensions/content/extensions.js"
  884.     }
  885.     return false;
  886.   },
  887.  
  888.   doCommand: function (aCommand)
  889.   {
  890.     if (this.isCommandEnabled(aCommand))
  891.       this.commands[aCommand](gExtensionsView.selectedItem);
  892.   },  
  893.   
  894.   onCommandUpdate: function ()
  895.   {
  896.     var extensionsCommands = document.getElementById("extensionsCommands");
  897.     for (var i = 0; i < extensionsCommands.childNodes.length; ++i)
  898.       this.updateCommand(extensionsCommands.childNodes[i]);
  899.   },
  900.   
  901.   updateCommand: function (command) 
  902.   {
  903.     if (this.isCommandEnabled(command.id))
  904.       command.removeAttribute("disabled");
  905.     else
  906.       command.setAttribute("disabled", "true");
  907.   },
  908.   
  909.   commands: { 
  910.     cmd_close: function (aSelectedItem)
  911.     {
  912.       closeWindow(true);
  913.     },  
  914.   
  915.     cmd_useTheme: function (aSelectedItem)
  916.     {
  917.       var pref = Components.classes["@mozilla.org/preferences-service;1"]
  918.                            .getService(Components.interfaces.nsIPrefBranch);
  919.       gCurrentTheme = aSelectedItem.getAttribute("internalName");
  920.       // Set this pref so the user can reset the theme in safe mode
  921.       pref.setCharPref(PREF_EM_LAST_SELECTED_SKIN, gCurrentTheme);
  922.  
  923.       if (pref.getBoolPref(PREF_EXTENSIONS_DSS_ENABLED)) {
  924.         pref.setCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN, gCurrentTheme);
  925.       }
  926.       else {
  927.         // Theme change will happen on next startup, this flag tells
  928.         // the Theme Manager that it needs to show "This theme will
  929.         // be selected after a restart" text in the selected theme
  930.         // item.
  931.         pref.setBoolPref(PREF_EXTENSIONS_DSS_SWITCHPENDING, true);
  932.         // Update the view
  933.         setRestartMessage(aSelectedItem);
  934.       }
  935.       
  936.       // disable the useThemeButton
  937.       gExtensionsViewController.onCommandUpdate();
  938.     },
  939.       
  940.     cmd_options: function (aSelectedItem)
  941.     {
  942.       if (!aSelectedItem) return;
  943.       var optionsURL = aSelectedItem.getAttribute("optionsURL");
  944.       if (optionsURL != "") {
  945.         var features;
  946.         try {
  947.           var prefs = Components.classes["@mozilla.org/preferences-service;1"]
  948.                                  .getService(Components.interfaces.nsIPrefBranch);
  949.           instantApply = prefs.getBoolPref("browser.preferences.instantApply");
  950.           features = "chrome,titlebar,toolbar,centerscreen" + (instantApply ? ",dialog=no" : ",modal");
  951.         }
  952.         catch (e) {
  953.           features = "chrome,titlebar,toolbar,centerscreen,modal";
  954.         }
  955.         openDialog(optionsURL, "", features);
  956.       }
  957.     },
  958.     
  959.     cmd_homepage: function (aSelectedItem)
  960.     {
  961.       if (!aSelectedItem) return;
  962.       var homepageURL = aSelectedItem.getAttribute("homepageURL");
  963.       // only allow http(s) homepages
  964.       var scheme = "";
  965.       var uri = null;
  966.       try {
  967.         uri = makeURI(homepageURL);
  968.         scheme = uri.scheme;
  969.       } catch (ex) {}
  970.       if (uri && (scheme == "http" || scheme == "https"))
  971.         openURL(uri.spec);
  972.     },
  973.     
  974.     cmd_about: function (aSelectedItem)
  975.     {
  976.       if (!aSelectedItem) return;
  977.       var aboutURL = aSelectedItem.getAttribute("aboutURL");
  978.       if (aboutURL != "")
  979.         openDialog(aboutURL, "", "chrome,modal");
  980.       else
  981.         openDialog("chrome://mozapps/content/extensions/about.xul", "", "chrome,modal", aSelectedItem.id, gExtensionsView.database);
  982.     },  
  983.     
  984.     cmd_movetop: function (aSelectedItem)
  985.     {
  986.       var movingID = aSelectedItem.id;
  987.       var moveTopID = gExtensionsView.children[0].id;
  988.       gExtensionManager.moveToIndexOf(movingID, moveTopID);
  989.     },
  990.     
  991.     cmd_moveup: function (aSelectedItem)
  992.     {
  993.       var movingID = aSelectedItem.id;
  994.       var moveAboveID = aSelectedItem.previousSibling.id;
  995.       gExtensionManager.moveToIndexOf(movingID, moveAboveID);
  996.     },
  997.     
  998.     cmd_movedn: function (aSelectedItem)
  999.     {
  1000.       var movingID = aSelectedItem.id;
  1001.       var moveBelowID = aSelectedItem.nextSibling.id;
  1002.       gExtensionManager.moveToIndexOf(movingID, moveBelowID);
  1003.     },
  1004.     
  1005.     cmd_update: function (aSelectedItem)
  1006.     { 
  1007.       var items = [];
  1008.       if (!aSelectedItem)
  1009.         items = gExtensionManager.getItemList(gItemType, { });
  1010.       else {
  1011.         var id = getIDFromResourceURI(aSelectedItem.id);
  1012.         items = [gExtensionManager.getItemForID(id)];
  1013.       }
  1014.       var listener = new UpdateCheckListener();
  1015.       gExtensionManager.update(items, items.length, false, listener);
  1016.     },
  1017.  
  1018.     cmd_update_all: function (aSelectedItem)
  1019.     {
  1020.       var items = gExtensionManager.getItemList(gItemType, { });
  1021.       var listener = new UpdateCheckListener();
  1022.       gExtensionManager.update(items, items.length, false, listener);
  1023.     },
  1024.  
  1025.     cmd_uninstall: function (aSelectedItem)
  1026.     {
  1027.       // Confirm the uninstall
  1028.       var extensionsStrings = document.getElementById("extensionsStrings");
  1029.       var brandStrings = document.getElementById("brandStrings");
  1030.  
  1031.       var name = aSelectedItem.getAttribute("name");
  1032.       var title = extensionsStrings.getFormattedString("queryUninstallTitle", [name]);
  1033.       if (gWindowState == "extensions")
  1034.         var message = extensionsStrings.getFormattedString("queryUninstallExtensionMessage", [name, name]);
  1035.       else if (gWindowState == "themes")
  1036.         message = extensionsStrings.getFormattedString("queryUninstallThemeMessage", [name]);
  1037.  
  1038.       // XXXben - improve the wording on the buttons here!
  1039.       var promptSvc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  1040.                                 .getService(Components.interfaces.nsIPromptService);
  1041.       if (!promptSvc.confirm(window, title, message))
  1042.         return;
  1043.  
  1044.       var selectedID = aSelectedItem.id;
  1045.       // if no next item, go to the previous one
  1046.       if (!gExtensionsView.goDown())
  1047.         gExtensionsView.goUp();
  1048.  
  1049.       if (gWindowState == "themes") {
  1050.         // If the theme being uninstalled is the current theme, we need to reselect
  1051.         // the default. 
  1052.         var pref = Components.classes["@mozilla.org/preferences-service;1"]
  1053.                              .getService(Components.interfaces.nsIPrefBranch);
  1054.         var currentTheme = pref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
  1055.         if (aSelectedItem.getAttribute("internalName") == currentTheme)
  1056.           this.cmd_useTheme(document.getElementById(PREFIX_ITEM_URI + "{972ce4c6-7e08-4474-a285-3208198ce6fd}"));
  1057.       }
  1058.       gExtensionManager.uninstallItem(getIDFromResourceURI(selectedID));
  1059.  
  1060.     },
  1061.  
  1062.     cmd_disable: function (aSelectedItem)
  1063.     {
  1064.       gExtensionManager.disableItem(getIDFromResourceURI(aSelectedItem.id));
  1065.     },
  1066.     
  1067.     cmd_enable: function (aSelectedItem)
  1068.     {
  1069.       gExtensionManager.enableItem(getIDFromResourceURI(aSelectedItem.id));
  1070. //@line 1114 "/c/mozilla/toolkit/mozapps/extensions/content/extensions.js"
  1071.     },
  1072.  
  1073.     cmd_install: function(aSelectedItem)
  1074.     {
  1075.       if (gWindowState == "extensions") 
  1076.         installExtension();
  1077.       else
  1078.         installSkin();
  1079.     }
  1080.   }
  1081. };
  1082.  
  1083. //////////////////////////////////////////////////////////////////////////
  1084. // functions to support installing of themes in apps other than firefox //
  1085. //////////////////////////////////////////////////////////////////////////
  1086. const nsIFilePicker = Components.interfaces.nsIFilePicker;
  1087. const nsIIOService = Components.interfaces.nsIIOService;
  1088. const nsIFileProtocolHandler = Components.interfaces.nsIFileProtocolHandler;
  1089. const nsIURL = Components.interfaces.nsIURL;
  1090.  
  1091. function installSkin()
  1092. {
  1093.   // 1) Prompt the user for the location of the theme to install. 
  1094.   var extensionsStrings = document.getElementById("extensionsStrings");
  1095.  
  1096.   var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
  1097.   fp.init(window, extensionsStrings.getString("installThemePickerTitle"), nsIFilePicker.modeOpen);
  1098.  
  1099.  
  1100.   fp.appendFilter(extensionsStrings.getString("themesFilter"), "*.jar");
  1101.   fp.appendFilters(nsIFilePicker.filterAll);
  1102.  
  1103.   var ret = fp.show();
  1104.   if (ret == nsIFilePicker.returnOK) 
  1105.   {
  1106.     var ioService = Components.classes['@mozilla.org/network/io-service;1'].getService(nsIIOService);
  1107.     var fileProtocolHandler =
  1108.     ioService.getProtocolHandler("file").QueryInterface(nsIFileProtocolHandler);
  1109.     var url = fileProtocolHandler.newFileURI(fp.file).QueryInterface(nsIURL);
  1110.     InstallTrigger.installChrome(InstallTrigger.SKIN, url.spec, decodeURIComponent(url.fileBaseName));
  1111.   }
  1112. }
  1113.  
  1114. function installExtension()
  1115. {
  1116.   var extensionsStrings = document.getElementById("extensionsStrings");
  1117.  
  1118.   var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
  1119.   fp.init(window, extensionsStrings.getString("installExtensionPickerTitle"), nsIFilePicker.modeOpen);
  1120.   
  1121.   fp.appendFilter(extensionsStrings.getString("extensionFilter"), "*.xpi");
  1122.   
  1123.   fp.appendFilters(nsIFilePicker.filterAll);
  1124.  
  1125.   var ret = fp.show();
  1126.   if (ret == nsIFilePicker.returnOK) 
  1127.   {
  1128.     var ioService = Components.classes['@mozilla.org/network/io-service;1'].getService(nsIIOService);
  1129.     var fileProtocolHandler =
  1130.     ioService.getProtocolHandler("file").QueryInterface(nsIFileProtocolHandler);
  1131.     var url = fileProtocolHandler.newFileURI(fp.file).QueryInterface(nsIURL);
  1132.     var xpi = {};
  1133.     xpi[decodeURIComponent(url.fileBaseName)] = url.spec;
  1134.     InstallTrigger.install(xpi);
  1135.   }
  1136. }
  1137.